/**
 * \file linked-list.h
 * \brief LinkedLista Ligada - Uma estrutura de dados dinámica.
 *
 * Esta lista ligada permite guardar em memória qualquer tipo de dados uma vez
 * que está a apontar para um valor void. Assim evita-se estar a definir
 * estruturas bastante semelhantes.
 */

# ifndef LIST_DEFINITION
# define LIST_DEFINITION

# include <stdlib.h>
# include "../../base/types.h"
# include "../../io/logs/logSystem.h"


/**
 * \struct Element
 * \brief Estrutura da Célula
 */
typedef struct Element {
	void *data;
	struct Element *next;
} LinkedList;

/**
 * \func LinkedList * newElem()
 * \brief Cria um novo elemento
 *
 * \warning Esta função pode em caso critico (em caso de não alocar memória) 
 * terminar com o programa. Para evitar isso será necessário garantir que o 
 * limite de memória nunca seja atingido.
 *
 * Básicamente aloca um espaço em memória e coloca os valor da estrutura 
 * Element a nulo.
 */
LinkedList * newElem();
/**
 * \func void * getData(LinkedList *elem)
 * \brief Dá os dados contidos no elemento
 * \param elem O elemento do qual extrair os dados.
 * 
 * Se o argumento for nulo devolve nulo.
 */
void * getData(LinkedList *elem);
/**
 * \func LinkedList * insertElemTail(LinkedList *list, void *data)
 * \brief Insere um elemento na cauda da lista
 *
 * Esta função tem de percorrer todos os elementos da lista, pelo que,
 * apresenta um tempo de execução linear no tamanho da lista.
 */
LinkedList * insertElemTail(LinkedList *list, void *data);
/**
 * \func LinkedList * insertElemHead(LinkedList *list, void *data)
 * \brief Insere um elemento à cabeça da lista
 *
 * Esta função executa em tempo constante.
 */
LinkedList * insertElemHead(LinkedList *list, void *data);
/**
 * \func LinkedList * nextElem (LinkedList *elem)
 * \brief Da o elemento seguinte.
 *
 * Egual a elem->next (apenas para manter uma abstracção)
 */
LinkedList * nextElem(LinkedList *elem);
/**
 * \func LinkedList * removeElem(LinkedList *list, void *data, equalFunction f)
 * \brief Remove o elemento da lista
 * \param list LinkedLista onde se encontra o elemento a remover
 * \param data Elemento a remover
 * \param f função que recebe dois elementos (void *) e diz se são iguais.
 * \return Lista sem o elemento
 *
 * \description
 * Da como resultado a lista sem o elemento. Só remove o primeiro (se 
 * existirem 2 ou mais iguais), se o elemento não existir devolve a mesma
 * lista.
 */
LinkedList * removeElem(LinkedList *list, void *data, equalFunction f);
/**
 * \brief Ve se existe proximo elemento
 * \param list Lista
 * \return 1 se sim 0 se não
 */
int hasNext (LinkedList *list);
/**
 * \brief Verifica se determinado elemento já existe
 * \param list Lista Ligada onde procurar o elemento
 * \param data Informação a procurar
 * \param f função de comparação
 * \return 1 se existir, 0 se não existir
 */
int existsElem (LinkedList *list, void *data, equalFunction f);

/**
 * \brief Ordena a lista
 * \param lst lista
 * \param f função de comparação (-1 menor 1 maior 0 igual)
 * \param desc 1 se for para rodernar descendentemente
 * \return lista ordenada
 */
LinkedList * sortList (LinkedList *lst, equalFunction f, int desc);
/**
 * \brief Da o tamanho da lista
 * \param list Lista
 * \return Tamanho da lista
 */
int listSize (LinkedList *list);

/**
 * \brief Junta duas listas numa só.
 * \param head Lista Principal
 * \param tail Lista que vai ficar ligada à cauda da head.
 * \return Lista com todos os elementos.
 */
LinkedList *mergeLists (LinkedList *head, LinkedList *tail);

/**
 * \brief Liberta a memoria desta estrutura
 */
void freeLinkedList (LinkedList * list);

# endif
